<template>
  <div ref="codeContainerRef" :style="{ height }" v-loading="loading"></div>
</template>

<script setup lang="ts">
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'
import './userWorker'
import { propTypes } from '@/utils/propTypes'
import { decodeStringToCharset } from '@/utils'
import { watch, onMounted, nextTick,ref,onBeforeUnmount } from 'vue'
const emit = defineEmits(['change-editor'])
const codeContainerRef = ref()
let editor: monaco.editor.IStandaloneCodeEditor
const props = defineProps({
  height: propTypes.oneOfType([Number, String]).def('100%'),
  readonly: propTypes.bool.def(false),
  modelValue: propTypes.oneOfType([String, Object]).def(''),
  language: propTypes.string.def('json'),
  theme: propTypes.string.def('vs-light'),
  isUpdateFormat: propTypes.bool.def(true) // 输入值时，是否格式化
})
const loading = ref(false)
watch(
  () => props.modelValue,
  () => {
    update()
  },
  { deep: true }
)
watch(
  () => props.language,
  () => {
    handleLanguageChange(props.language)
  },
  { deep: true }
)

const init = () => {
  // 注册自定义主题 TODO:自定义主题高亮色还没配置
  // Object.keys(MsCodeEditorTheme).forEach((e) => {
  //   monaco.editor.defineTheme(e, MsCodeEditorTheme[e as CustomTheme]);
  // });
  loading.value = true
  try {
    if (!codeContainerRef.value) return
    editor = monaco.editor.create(codeContainerRef.value, {
      value: props.modelValue,
      automaticLayout: true,
      padding: {
        top: 12,
        bottom: 12
      },
      // wordWrap:'on',
      minimap: {
        enabled: false // 将代码块预览隐藏
      },
      stickyScroll: {
        enabled: false
      },
      contextmenu: !props.readOnly, // 只读模式下禁用右键菜单
      ...props,
      lineNumbersMinChars: 3,
      lineDecorationsWidth: 0,
      tabSize: 2,
      // 开启自动格式化
      formatOnType: true,
      scrollBeyondLastLine: false // 内容超出初始化后的最后一行才显示滚动条
    })
    editor.getModel()?.setEOL(monaco.editor.EndOfLineSequence.LF) // 设置换行符
    // 监听值的变化
    editor.onDidChangeModelContent(() => {
      const value = editor.getValue() // 给父组件实时返回最新文本
      emit('change-editor', value)
      props.isUpdateFormat && formatFn()
    })
    formatFn()
  } catch (error) {
    console.log(error)
  } finally {
    loading.value = false
  }
}

const handleLanguageChange = (val: string) => {
  if (editor) {
    monaco.editor.setModelLanguage(editor.getModel()!, val?.toLowerCase())
    formatFn()
  }
}
const handleCharsetChange = (val: string) => {
  if (editor) {
    editor.setValue(decodeStringToCharset(props.modelValue, val))
    formatFn()
  }
}

const update = () => {
  if (editor) {
    if (props.modelValue) {
      editor.setValue(props.modelValue)
      formatFn()
    } else {
      editor.setValue('')
    }
  }
}
const reset = () => {
  editor.setValue('')
}
const formatFn = () => {
  setTimeout(() => {
    const formatAction = editor.getAction('editor.action.formatDocument')
    if (formatAction) {
      formatAction.run()
    }
  }, 500)
}
defineExpose({ handleLanguageChange, handleCharsetChange, update, reset, formatFn }) // 提供 open 方法，用于打开弹窗

onMounted(() => {
  nextTick(() => {
    !editor && init()
  })
})

onBeforeUnmount(() => {
  if (editor) {
    editor.dispose()
  }
})
</script>

<style scoped></style>
